/*-
 * Copyright (c) 2012-2013 Shang-Rong Cai. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $ MTBLAS TEST: tst_lv_1_nrm.c    Rev. 0.0.8    2013-11-15T17:20+08:00 $
 */

#include <stdio.h>
#include <complex.h>
#include <time.h>
#include <math.h>

#include <cblas.h>

#include <tst_lv_a_com.h>

int test_nrm2f(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_ff_t vx;

    float buf_st;  /* Single-thread return */
    float buf_mt;  /* Multi-threads return */
    float buf_cf;  /* cblas return */

    struct timespec tp_b;  /* Time of test begin */
    struct timespec tp_e;  /* Time of test end */

    double cst_st;
    double cst_mt;
    double cst_cf;

    ierr = vec_ff_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    clock_gettime(CLOCK_REALTIME, &tp_b);
    ierr = stblas_nrm2f(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    clock_gettime(CLOCK_REALTIME, &tp_e);
    cst_st = clock_difftime(&tp_b, &tp_e);

    clock_gettime(CLOCK_REALTIME, &tp_b);
    ierr = mtblas_nrm2f(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    clock_gettime(CLOCK_REALTIME, &tp_e);
    cst_mt = clock_difftime(&tp_b, &tp_e);

    clock_gettime(CLOCK_REALTIME, &tp_b);
    buf_cf = cblas_snrm2(LV1_VECTOR_RUN, vx.data, vx.step);
    clock_gettime(CLOCK_REALTIME, &tp_e);
    cst_cf = clock_difftime(&tp_b, &tp_e);

    printf("nrm2f() -> cblas_snrm2()\n");
    check_value_ff_stdout("    ST:", buf_st);
    check_value_ff_stdout("    MT:", buf_mt);
    check_value_ff_stdout("    CF:", buf_cf);

    printf("Time Cost: %10.3lf, %10.3lf, %10.3lf\n", cst_st, cst_mt, cst_cf);

    ierr = vec_ff_delete(&vx);

    return ierr;
}


int stblas_nrm2_test(const size_t sz, const double *vx, const step_t incx, double *rbuf)
{
    int ierr = ERRNO_UNDEFINED;
    void *ptr_vx, *end_vx;
    size_t step_incx;

    ptr_vx = (void*) vx;
    step_incx = 8 * incx;
    end_vx = (void*) vx + sz * step_incx;

    *rbuf = 0;
    while (ptr_vx < end_vx)
    {
        *rbuf += *((double*) ptr_vx) * *((double*) ptr_vx);
        ptr_vx += step_incx;
    }
    *rbuf = sqrt(*rbuf);

    return ierr;
}


int stblas_nrm2_test_2(const size_t sz, const double *vx, const step_t incx, double *rbuf)
{
    int ierr = ERRNO_UNDEFINED;
    void *ptr_vx;
    size_t step_incx;

    step_incx = 8 * incx;

    *rbuf = 0;
    for (ptr_vx = (void*) vx; ptr_vx < (void*) vx + sz * step_incx; ptr_vx += step_incx)
    {
        *rbuf += *((double*) ptr_vx) * *((double*) ptr_vx);
    }
    *rbuf = sqrt(*rbuf);

    return ierr;
}


int test_nrm2(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_df_t vx;

    double buf_st;  /* Single-thread return */
    double buf_mt;  /* Multi-threads return */
    double buf_cf;  /* cblas return */

    struct timespec tp_b;  /* Time of test begin */
    struct timespec tp_e;  /* Time of test end */

    double cst_st;
    double cst_mt;
    double cst_cf;

    ierr = vec_df_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    clock_gettime(CLOCK_REALTIME, &tp_b);
    //ierr = stblas_nrm2(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = stblas_nrm2_test(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    clock_gettime(CLOCK_REALTIME, &tp_e);
    cst_st = clock_difftime(&tp_b, &tp_e);

    clock_gettime(CLOCK_REALTIME, &tp_b);
    ierr = mtblas_nrm2(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    clock_gettime(CLOCK_REALTIME, &tp_e);
    cst_mt = clock_difftime(&tp_b, &tp_e);

    clock_gettime(CLOCK_REALTIME, &tp_b);
    buf_cf = cblas_dnrm2(LV1_VECTOR_RUN, vx.data, vx.step);
    clock_gettime(CLOCK_REALTIME, &tp_e);
    cst_cf = clock_difftime(&tp_b, &tp_e);

    printf("nrm2() -> cblas_dnrm2()\n");
    check_value_df_stdout("    ST:", buf_st);
    check_value_df_stdout("    MT:", buf_mt);
    check_value_df_stdout("    CF:", buf_cf);

    printf("Time Cost: %10.3lf, %10.3lf, %10.3lf\n", cst_st, cst_mt, cst_cf);

    ierr = vec_df_delete(&vx);

    return ierr;
}


int test_nrm2l(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_lf_t vx;

    long double buf_st;  /* Single-thread return */
    long double buf_mt;  /* Multi-threads return */

    ierr = vec_lf_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_nrm2l(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_nrm2l(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);

    printf("nrm2l()\n");
    check_value_lf_stdout("    ST:", buf_st);
    check_value_lf_stdout("    MT:", buf_mt);

    ierr = vec_lf_delete(&vx);

    return ierr;
}


int test_cnrm2f(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_fc_t vx;

    float buf_st;  /* Single-thread return */
    float buf_mt;  /* Multi-threads return */
    float buf_cf;  /* cblas return */

    ierr = vec_fc_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_cnrm2f(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_cnrm2f(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_scnrm2(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("cnrm2f() -> cblas_scnrm2()\n");
    check_value_ff_stdout("    ST:", buf_st);
    check_value_ff_stdout("    MT:", buf_mt);
    check_value_ff_stdout("    CF:", buf_cf);

    ierr = vec_fc_delete(&vx);

    return ierr;
}


int test_cnrm2(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_dc_t vx;

    double buf_st;  /* Single-thread return */
    double buf_mt;  /* Multi-threads return */
    double buf_cf;  /* cblas return */

    ierr = vec_dc_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_cnrm2(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_cnrm2(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_dznrm2(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("cnrm2() -> cblas_dznrm2()\n");
    check_value_df_stdout("    ST:", buf_st);
    check_value_df_stdout("    MT:", buf_mt);
    check_value_df_stdout("    CF:", buf_cf);

    ierr = vec_dc_delete(&vx);

    return ierr;
}


int test_cnrm2l(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_lc_t vx;

    long double buf_st;  /* Single-thread return */
    long double buf_mt;  /* Multi-threads return */

    ierr = vec_lc_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_cnrm2l(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_cnrm2l(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);

    printf("cnrm2l()\n");
    check_value_lf_stdout("    ST:", buf_st);
    check_value_lf_stdout("    MT:", buf_mt);

    ierr = vec_lc_delete(&vx);

    return ierr;
}


int test_asumf(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_ff_t vx;

    float buf_st;  /* Single-thread return */
    float buf_mt;  /* Multi-threads return */
    float buf_cf;  /* cblas return */

    ierr = vec_ff_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_asumf(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_asumf(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_sasum(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("asumf() -> cblas_sasum()\n");
    check_value_ff_stdout("    ST:", buf_st);
    check_value_ff_stdout("    MT:", buf_mt);
    check_value_ff_stdout("    CF:", buf_cf);

    ierr = vec_ff_delete(&vx);

    return ierr;
}


int test_asum(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_df_t vx;

    double buf_st;  /* Single-thread return */
    double buf_mt;  /* Multi-threads return */
    double buf_cf;  /* cblas return */

    ierr = vec_df_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_asum(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_asum(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_dasum(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("asumf() -> cblas_dasum()\n");
    check_value_df_stdout("    ST:", buf_st);
    check_value_df_stdout("    MT:", buf_mt);
    check_value_df_stdout("    CF:", buf_cf);

    ierr = vec_df_delete(&vx);

    return ierr;
}


int test_asuml(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_lf_t vx;

    long double buf_st;  /* Single-thread return */
    long double buf_mt;  /* Multi-threads return */

    ierr = vec_lf_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_asuml(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_asuml(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);

    printf("asuml()()\n");
    check_value_lf_stdout("    ST:", buf_st);
    check_value_lf_stdout("    MT:", buf_mt);

    ierr = vec_lf_delete(&vx);

    return ierr;
}


int test_casumf(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_fc_t vx;

    float buf_st;  /* Single-thread return */
    float buf_mt;  /* Multi-threads return */
    float buf_cf;  /* cblas return */

    ierr = vec_fc_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_casumf(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_casumf(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_scasum(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("casumf() -> cblas_scasum()\n");
    check_value_ff_stdout("    ST:", buf_st);
    check_value_ff_stdout("    MT:", buf_mt);
    check_value_ff_stdout("    CF:", buf_cf);

    ierr = vec_fc_delete(&vx);

    return ierr;
}


int test_casum(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_dc_t vx;

    double buf_st;  /* Single-thread return */
    double buf_mt;  /* Multi-threads return */
    double buf_cf;  /* cblas return */

    ierr = vec_dc_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_casum(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_casum(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_dzasum(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("casum() -> cblas_dzasum()\n");
    check_value_df_stdout("    ST:", buf_st);
    check_value_df_stdout("    MT:", buf_mt);
    check_value_df_stdout("    CF:", buf_cf);

    ierr = vec_dc_delete(&vx);


    return ierr;
}


int test_casuml(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_lc_t vx;

    long double buf_st;  /* Single-thread return */
    long double buf_mt;  /* Multi-threads return */

    ierr = vec_lc_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_casuml(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_casuml(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);

    printf("casuml()\n");
    check_value_lf_stdout("    ST:", buf_st);
    check_value_lf_stdout("    MT:", buf_mt);

    ierr = vec_lc_delete(&vx);


    return ierr;
}


int test_iamaxf(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_ff_t vx;

    sidx_t buf_st;  /* Single-thread return */
    sidx_t buf_mt;  /* Multi-threads return */
    size_t buf_cf;  /* cblas return */

    ierr = vec_ff_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_iamaxf(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_iamaxf(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_isamax(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("iamaxf() -> cblas_isamax() NEW\n");
    printf("    ST: %8ld, value: % .6E\n", buf_st, vx.data[buf_st]);
    printf("    MT: %8ld, value: % .6E\n", buf_mt, vx.data[buf_mt]);
    printf("    CF: %8zd, value: % .6E\n", buf_cf, vx.data[buf_cf]);

    ierr = vec_ff_delete(&vx);

    return ierr;
}


int test_iamax(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_df_t vx;

    sidx_t buf_st;  /* Single-thread return */
    sidx_t buf_mt;  /* Multi-threads return */
    size_t buf_cf;  /* cblas return */

    ierr = vec_df_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_iamax(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_iamax(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);
    buf_cf = cblas_idamax(LV1_VECTOR_RUN, vx.data, vx.step);

    printf("iamaxf() -> cblas_idamax() NEW\n");
    printf("    ST: %8ld, value: % .15lE\n", buf_st, vx.data[buf_st]);
    printf("    MT: %8ld, value: % .15lE\n", buf_mt, vx.data[buf_mt]);
    printf("    CF: %8zd, value: % .15lE\n", buf_cf, vx.data[buf_cf]);

    ierr = vec_df_delete(&vx);

    return ierr;
}


int test_iamaxl(size_t thrz)
{
    int ierr = ERRNO_UNDEFINED;
    vec_lf_t vx;

    sidx_t buf_st;  /* Single-thread return */
    sidx_t buf_mt;  /* Multi-threads return */

    ierr = vec_lf_create(LV1_VECTOR_MAX, LV1_VECTOR_MIN, LV1_VECTOR_RUN, &vx);

    ierr = stblas_iamaxl(LV1_VECTOR_RUN, vx.data, vx.step, &buf_st);
    ierr = mtblas_iamaxl(thrz, LV1_VECTOR_RUN, vx.data, vx.step, &buf_mt);

    printf("iamaxf() -> cblas_idamax() NEW\n");
    printf("    ST: %8ld, value: % .33LE\n", buf_st, vx.data[buf_st]);
    printf("    MT: %8ld, value: % .33LE\n", buf_mt, vx.data[buf_mt]);

    ierr = vec_lf_delete(&vx);

    return ierr;
}
